/**
* Analytica - beta version - Systems Monitoring Tool
*
* Copyright (C) 2013, KleeGroup, direction.technique@kleegroup.com (http://www.kleegroup.com)
* KleeGroup, Centre d'affaire la Boursidi�re - BP 159 - 92357 Le Plessis Robinson Cedex - France
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation;
* either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, see <http://www.gnu.org/licenses>
*
* Linking this library statically or dynamically with other modules is making a combined work based on this library.
* Thus, the terms and conditions of the GNU General Public License cover the whole combination.
*
* As a special exception, the copyright holders of this library give you permission to link this library
* with independent modules to produce an executable, regardless of the license terms of these independent modules,
* and to copy and distribute the resulting executable under terms of your choice, provided that you also meet,
* for each linked independent module, the terms and conditions of the license of that module.
* An independent module is a module which is not derived from or based on this library.
* If you modify this library, you may extend this exception to your version of the library,
* but you are not obliged to do so.
* If you do not wish to do so, delete this exception statement from your version.
*/
package io.analytica.spies.imp.javassist;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Implementation d'un agent de jvm.
* Celui ci doit etre inclus dans un jar et pass� en parametre � la jvm :
* <code>-javaagent:"monjar.jar"=option</code>
* Ce jar doit avoir un manifest qui contient la ligne suivante :
* <code>Premain-Class: io.analytica.spies.imp.javassist.AnalyticaSpyAgent</code>
*
* Cet agent ajoute un ClassFileTransformer sp�cifique qui a pour but d'instrumenter
* les m�thodes selon un param�trage externe.
* L'option de l'agent dans la ligne de commande repr�sente le nom du fichier de param�trage.
*
* @author npiedeloup
* @version $Id: MemoryLeakAgent.java,v 1.2 2012/09/28 09:30:03 pchretien Exp $
*/
public final class AnalyticaSpyAgent {
private static Instrumentation instrumentation;
private static ClassFileTransformer transformer;
private AnalyticaSpyAgent() {
//rien
}
/**
* Methode respectant l'API (sans interface java) pour l'utilisation de -javaagent.
* @param agentArgs parametre <code>option</code> de la ligne de commande
* @param inst Instrumentation modifiable fournit par la JVM
*/
public static void premain(final String agentArgs, final Instrumentation inst) {
//System.out.println("premain method invoked with args: {" + agentArgs + "} and inst: {" + inst + "}");
addTransformer(agentArgs, inst, false);
}
/**
* Methode respectant l'API (sans interface java) pour le chargement de l'agent apres d�marrage de la JVM.
* @param agentArgs parametre <code>option</code> de la ligne de commande
* @param inst Instrumentation modifiable fournit par la JVM
*/
public static void agentmain(final String agentArgs, final Instrumentation inst) {
//System.out.println("agentmain method invoked with args: {" + agentArgs + "} and inst: {" + inst + "}");
addTransformer(agentArgs, inst, true);
}
public static void stopAgent() {
if (instrumentation != null && transformer != null) {
instrumentation.removeTransformer(transformer);
reloadAll();
instrumentation = null;
transformer = null;
System.out.println("AnalyticaAgent Stop at " + new Date());
}
}
public static void reloadAll() {
//code < jdk1.6 : can't reload
System.out.println("AnalyticaAgent reload All");
doReload(obtainInstrumentedClasses());
}
private static void addTransformer(final String agentArgs, final Instrumentation inst, final boolean canRetransform) {
if (instrumentation == null) {
instrumentation = inst;
System.out.println("AnalyticaAgent prepare at " + new Date());
transformer = new AnalyticaSpyTransformer(agentArgs);
//code jdk1.6+ inst.addTransformer(transformer, canRetransform);
// code jdk1.5 : inst.addTransformer(transformer);
inst.addTransformer(transformer, canRetransform);
System.out.println("AnalyticaAgent Start at " + new Date());
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
AnalyticaSpyAgent.stopAgent();
}
});
reloadAll();
}
}
private static Class<?>[] obtainInstrumentedClasses() {
final Class<?>[] allLoadedClasses = instrumentation.getAllLoadedClasses();
final List<Class<?>> classes = new ArrayList<Class<?>>(allLoadedClasses.length);
for (final Class<?> clazz : allLoadedClasses) {
if (((AnalyticaSpyTransformer) transformer).shouldTransform(clazz.getClassLoader(), clazz.getName())) {
classes.add(clazz);
}
}
return classes.toArray(new Class[classes.size()]);
}
// private static void reload(final Class<?>... classes) {
// System.out.println("AnalyticaAgent reload " + Arrays.asList(classes));
// doReload(classes);
// }
private static void doReload(final Class<?>... classes) {
for (final Class<?> clazz : classes) {
try {
//code jdk1.6+ : instrumentation.retransformClasses(clazz);
//code jdk1.5 : can't reload
instrumentation.retransformClasses(clazz);
} catch (final Throwable e) {
System.err.println("Erreur retransformClasses " + clazz.getName() + " : (" + e.getClass().getName() + ") " + e.getMessage());
//throw e;
}
}
}
}